﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LotteryVote.Data;
using LotteryVote.Entity;
using LotteryVote.Utility;
using LotteryVote.Logic.Exceptions;
using LotteryVote.Logic.Application;
using LotteryVote.Logic.Limit;
using System.Text.RegularExpressions;

namespace LotteryVote.Logic
{
    public class DropWaterFacade
    {
        private DropWaterDataAccess _daDropWater;
        internal DropWaterDataAccess DaDropWater
        {
            get
            {
                if (_daDropWater == null)
                    _daDropWater = new DropWaterDataAccess();
                return _daDropWater;
            }
            set
            {
                _daDropWater = value;
            }
        }

        private GamePlayWayDataAccess _daGamePlayWay;
        internal GamePlayWayDataAccess DaGamePlayWay
        {
            get
            {
                if (_daGamePlayWay == null)
                    _daGamePlayWay = new GamePlayWayDataAccess();
                return _daGamePlayWay;
            }
            set
            {
                _daGamePlayWay = value;
            }
        }

        private LotteryCompanyDataAccess _daCompany;
        internal LotteryCompanyDataAccess DaCompany
        {
            get
            {
                if (_daCompany == null)
                    _daCompany = new LotteryCompanyDataAccess();
                return _daCompany;
            }
            set
            {
                _daCompany = value;
            }
        }

        /// <summary>
        /// 新增今日跌水限制
        /// </summary>
        /// <param name="num">号码.</param>
        /// <param name="gamePlayWayId">玩法.</param>
        /// <param name="dropValue">跌水值.</param>
        /// <param name="amount">金额.</param>
        /// <param name="companyId">公司.</param>
        public void AddDropWater(string num, int gamePlayWayId, double dropValue, decimal amount, params int[] companyIds)
        {
            CheckDropWaterValid(num, gamePlayWayId, dropValue, amount, companyIds);

            var gameplayway = LotterySystem.Current.GamePlayWay.Find(it => it.Id == gamePlayWayId);
            var dropWaters = DaDropWater.ListDropWater(num, DateTime.Today);
            var dropWater = dropWaters.Find(it => it.GamePlayWayId == gamePlayWayId && it.Amount == amount && it.DropValue == dropValue);

            if (IsRangeNum(num))
            {
                foreach (var n in GetRangeNum(num))
                    AddDropWater(n, gamePlayWayId, dropValue, amount, companyIds);

                return;
            }

            foreach (var companyId in companyIds)
            {
                var company = DaCompany.GetCompany(companyId);
                if (dropWater != null)
                {
                    if (DaDropWater.CountDropWater(dropWater.DropId, companyId) > 0)        //公司已添加该跌水的
                        throw new PromptException("num:{0} has drop when amount equals {1} and company equals {2} and play way equals {3}!",
                            num, amount, company.Name, gameplayway.PlayWay.WayName);
                    DaDropWater.Insert(dropWater, company);
                }
                else
                {
                    //同种玩法，同个跌水金额，不同跌水率
                    dropWater = dropWaters.Find(it => it.GamePlayWayId == gamePlayWayId && it.Amount == amount);
                    if (dropWater != null)
                        throw new PromptException("num:{0} has drop when amount equals {1} and company equals {2} and play way equals {3}!",
                        num, amount, company.Name, gameplayway.PlayWay.WayName);
                    dropWater = new DropWater
                    {
                        Num = num,
                        DropType = DropType.Manual,
                        DropValue = dropValue,
                        Amount = amount,
                        GamePlayWayId = gameplayway.Id
                    };
                    DaDropWater.ExecuteWithTransaction(() =>
                    {
                        DaDropWater.Insert(dropWater);
                        DaDropWater.Insert(dropWater, company);
                        LimitContext.Instance.UpdateCacheUpperLimitToDB(DaDropWater);
                    });
                }
            }
        }
        /// <summary>
        /// 添加自动跌水规则.
        /// </summary>
        /// <param name="num">The num.</param>
        /// <param name="gameplaywayId">The gameplayway id.</param>
        /// <param name="dropValue">The drop value.</param>
        /// <param name="amount">The amount.</param>
        public void AddAutoDropWater(string num, int gameplaywayId, double dropValue, decimal amount)
        {
            if (dropValue < 0)
                throw new ArgumentException("drop value");
            if (amount < 0)
                throw new ArgumentException("amount");
            var drop = DaDropWater.GetManualDropWater(num, gameplaywayId, amount);
            if (drop != null)
                throw new PromptException("drop water was exist!");
            drop = new DropWater
            {
                Num = num,
                GamePlayWayId = gameplaywayId,
                DropValue = dropValue,
                Amount = amount,
                DropType = DropType.Auto
            };
            DaDropWater.Insert(drop);
        }
        /// <summary>
        /// 添加2D的自动跌水限制.
        /// </summary>
        /// <param name="dropValue">跌水值.</param>
        /// <param name="dropAmount">跌水金额.</param>
        public void Add2DAutoDropWater(float dropValue, decimal dropAmount)
        {
            if (dropValue >= 100)
                throw new ArgumentException("dropValue can't equals 100.");
            if (HasAutoDropWater(2, dropAmount))
                throw new PromptException("2D has some auto drop which it's amount equals {0},Please delete them!", dropAmount);
            var gamePlayWay = DaGamePlayWay.GetGamePlayWayByGameType(GameTypeEnum.TwoDigital);
            int notIncludePlayWay = (int)PlayWayEnum.HeadAndLast;
            var insertGamePlayWay = gamePlayWay.Where(it => it.PlayWay.WayId != notIncludePlayWay);
            string[] numArr = new string[100];
            for (int i = 0; i < 100; i++)
                numArr[i] = i.ToString("D2");
            List<DropWater> dropWaterList = new List<DropWater>();
            foreach (var gpw in insertGamePlayWay)
                foreach (var num in numArr)
                {
                    dropWaterList.Add(new DropWater
                    {
                        Num = num,
                        GamePlayWayId = gpw.Id,
                        DropType = DropType.Auto,
                        DropValue = dropValue,
                        Amount = dropAmount
                    });
                }
            DaDropWater.ExecuteWithTransaction(() =>
            {
                dropWaterList.ForEach(it =>
                {
                    DaDropWater.Insert(it);
                });
            });
        }
        public void RemoveDropWater(int dropId)
        {
            //TODO:检查限制
            DaDropWater.Delete(dropId);
        }
        /// <summary>
        /// 是否存在指定长度号码，指定金额的自动跌水限制
        /// </summary>
        /// <param name="numLen">The num len.</param>
        /// <param name="amount">The amount.</param>
        /// <returns>
        ///   <c>true</c> if [has auto drop water] [the specified num len]; otherwise, <c>false</c>.
        /// </returns>
        public bool HasAutoDropWater(int numLen, decimal amount)
        {
            return DaDropWater.CountAutoDropWater(numLen, amount) > 0;
        }
        public IList<DropWater> ListAutoDropWater(int pageItemCount, int pageIndex, out int totalCount)
        {
            totalCount = DaDropWater.CountDropWater(DropType.Auto);
            return DaDropWater.ListDropWater(DropType.Auto, pageItemCount, pageIndex);
        }
        public IList<DropWater> ListAutoDropWaterByCondition(string num, int companyId, int gameplaywayId, double dropvalue,
            decimal amount, int pageItemCount, int pageIndex, out int totalCount)
        {
            totalCount = DaDropWater.CountDropWaterByCondition(DropType.Auto, null, num, companyId, gameplaywayId, dropvalue, amount);
            return DaDropWater.ListDropWaterByCondition(DropType.Auto, null, num, companyId, gameplaywayId, dropvalue, amount, pageItemCount, pageIndex);
        }
        public IList<DropWater> ListTodayManualDropWater(int pageItemCount, int pageIndex, out int totalCount)
        {
            totalCount = DaDropWater.CountDropWater(DropType.Manual, DateTime.Today);
            return DaDropWater.ListDropWater(DropType.Manual, pageItemCount, pageIndex, DateTime.Today);
        }
        public IList<DropWater> ListTodayManualDropWaterByCondition(string num, int companyId, int gameplaywayId, double dropvalue,
            decimal amount, int pageItemCount, int pageIndex, out int totalCount)
        {
            totalCount = DaDropWater.CountDropWaterByCondition(DropType.Manual, DateTime.Today, num, companyId, gameplaywayId, dropvalue, amount);
            return DaDropWater.ListDropWaterByCondition(DropType.Manual, DateTime.Today, num, companyId, gameplaywayId, dropvalue, amount, pageItemCount, pageIndex);
        }

        private void CheckDropWaterValid(string num, int gamePlayWayId, double dropValue, decimal amount, params int[] companyIds)
        {
            if (string.IsNullOrEmpty(num))
                throw new ArgumentException("num");
            if (dropValue < 0)
                throw new ArgumentException("drop value");
            if (amount < 0)
                throw new ArgumentException("amount");
            if (gamePlayWayId <= 0)
                throw new PromptException("请选择一个玩法！");
            if (companyIds.Length < 0)
                throw new ArgumentException("companyIds");
            foreach (int companyId in companyIds)
            {
                var upperLimit = LimitContext.Instance.CacheUpperLimitList.Find(it => it.Num == num && it.GamePlayWayId == gamePlayWayId && it.CompanyId == companyId);
                if (upperLimit != null)
                    if (upperLimit.NextLimit == upperLimit.UpperLlimit) //下次限制已是最大限制
                    {
                        if (amount < upperLimit.TotalBetAmount)
                            throw new PromptException("跌水金额必须大于{0}!", upperLimit.TotalBetAmount);
                        upperLimit.NextLimit = amount;
                    }
                    else if (upperLimit.NextLimit < upperLimit.UpperLlimit)//还存在佣金跌水
                    {
                        //新增跌水规则金额必须大于当前限制跌水金额且必须大于已投金额
                        if (upperLimit.NextLimit > amount || amount < upperLimit.TotalBetAmount)
                            throw new PromptException("跌水金额必须大于{0}并且小于{1}!", upperLimit.TotalBetAmount, upperLimit.NextLimit);
                    }
                    else
                        throw new PromptException("不能添加跌水，跌水金额已超出投注上限！");
            }

        }


        /// <summary>
        ///是否连号，例如-10代表所有以10结尾的3位数，--10代表以10结尾的4位数
        /// </summary>
        /// <param name="num">The num.</param>
        /// <returns>
        ///   <c>true</c> if [is range num] [the specified num]; otherwise, <c>false</c>.
        /// </returns>
        private bool IsRangeNum(string num)
        {
            Regex rule = new Regex(@"^-+\d+$");
            return rule.IsMatch(num);
        }
        private IEnumerable<string> GetRangeNum(string num)
        {
            if (num.Length > 5) throw new PromptException("仅支持5D及其下号码！");
            if (!IsRangeNum(num)) return new string[0];
            List<string> rangNumList = new List<string>();
            int numIndex = num.LastIndexOf('-') + 1;
            string n = num.Substring(numIndex);
            int rangeNumLen = num.Length - n.Length;
            for (int i = 0; i < Math.Pow(10, rangeNumLen); i++)
            {
                rangNumList.Add(i.ToString("D" + rangeNumLen) + n);
            }
            return rangNumList;
        }
    }
}
